package dk.cs.au.peterbn.patterns;

import dk.au.cs.peterbn.patterns.*;
import org.junit.Before;
import org.junit.Test;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import static org.junit.Assert.*;

/**
 * Test case for correct pattern deserialization
 */
public class XmlDeserialization {

    private PatternProvider patternProvider;

    @Before
    public void init() {
        patternProvider = new PatternProvider();
    }

    @Test
    public void strategy() throws Exception {
        DesignPattern pattern = patternProvider.getDesignPattern("gof:Strategy");
        System.out.println(pattern.getDescription());
        assertEquals("gof", pattern.getGroup());
        assertEquals("Strategy", pattern.getName());
        Collection<TypeRole> types = pattern.getTypes();
        assertEquals(3, types.size());
        assertNotNull(pattern.getTypeRole("Context"));
        assertNotNull(pattern.getTypeRole("Strategy"));
        assertNotNull(pattern.getTypeRole("ConcreteStrategy"));

        Map<String, MemberRole> members = getMembers(types);
        assertEquals(1, members.size());
        MemberRole algorithmInterface = pattern.getMember("AlgorithmInterface");
        assertNotNull(algorithmInterface);

        assertEquals(1,algorithmInterface.getCallSites().size());
    }

    @Test
    public void state() throws Exception {
        DesignPattern pattern = patternProvider.getDesignPattern("gof:State");
        System.out.println(pattern.getDescription());
        assertEquals("gof", pattern.getGroup());
        assertEquals("State", pattern.getName());
        Collection<TypeRole> types = pattern.getTypes();
        assertEquals(3, types.size());
        assertNotNull(pattern.getTypeRole("Context"));
        assertNotNull(pattern.getTypeRole("State"));
        assertNotNull(pattern.getTypeRole("ConcreteState"));
        Map<String, MemberRole> members = getMembers(types);
        assertEquals(2, members.size());
        assertNotNull(pattern.getMember("Handle"));
        assertNotNull(pattern.getMember("Request"));
    }

    @Test
    public void observer() throws Exception {
        DesignPattern pattern = patternProvider.getDesignPattern("gof:Observer");
        System.out.println(pattern.getDescription());
        assertEquals("gof", pattern.getGroup());
        assertEquals("Observer", pattern.getName());
        Collection<TypeRole> types = pattern.getTypes();
        assertEquals(4, types.size());
        assertNotNull(pattern.getTypeRole("Observer"));
        assertNotNull(pattern.getTypeRole("ConcreteObserver"));
        assertNotNull(pattern.getTypeRole("Subject"));
        assertNotNull(pattern.getTypeRole("ConcreteSubject"));
        Map<String, MemberRole> members = getMembers(types);
        assertEquals(6, members.size());
        assertNotNull(pattern.getMember("Attach"));
        assertNotNull(pattern.getMember("Detach"));
        assertNotNull(pattern.getMember("Notify"));
        assertNotNull(pattern.getMember("GetState"));
        assertNotNull(pattern.getMember("SetState"));
        assertNotNull(pattern.getMember("Update"));
    }

    @Test
    public void observerEventVariation() throws Exception {
        DesignPattern pattern = patternProvider.getDesignPattern("gof:Observer/Push");
        System.out.println(pattern.getDescription());
        assertEquals("gof", pattern.getGroup());
        assertEquals("Observer", pattern.getName());
        assertEquals("Event", pattern.getVariation());
        Collection<TypeRole> types = pattern.getTypes();
        assertEquals(5, types.size());

        assertNotNull(pattern.getTypeRole("Observer"));
        assertNotNull(pattern.getTypeRole("ConcreteObserver"));
        assertNotNull(pattern.getTypeRole("Subject"));
        assertNotNull(pattern.getTypeRole("ConcreteSubject"));
        assertNotNull(pattern.getTypeRole("Event"));

        Map<String, MemberRole> members = getMembers(types);
        assertEquals(5, members.size());

        assertNotNull(pattern.getMember("Attach"));
        assertNotNull(pattern.getMember("Detach"));
        assertNotNull(pattern.getMember("Notify"));
        assertNotNull(pattern.getMember("GetData"));
        assertNotNull(pattern.getMember("Update"));
    }

    @Test
    public void abstractFactory() throws Exception {
        DesignPattern pattern = patternProvider.getDesignPattern("gof:AbstractFactory");
        System.out.println(pattern.getDescription());
        assertEquals("gof", pattern.getGroup());
        assertEquals("AbstractFactory", pattern.getName());
        Collection<TypeRole> types = pattern.getTypes();
        assertEquals(5, types.size());
        assertNotNull(pattern.getTypeRole("AbstractFactory"));
        assertNotNull(pattern.getTypeRole("ConcreteFactory"));
        assertNotNull(pattern.getTypeRole("AbstractProduct"));
        assertNotNull(pattern.getTypeRole("ConcreteProduct"));
        assertNotNull(pattern.getTypeRole("Client"));
        Map<String, MemberRole> members = getMembers(types);
        assertEquals(1, members.size());
        assertNotNull(pattern.getMember("CreateProduct"));
    }

    @Test(expected = InvalidPatternException.class)
    public void invalidPattern() throws Exception {
        DesignPattern designPattern = patternProvider.getDesignPattern("foo:Bar");
        assertNull(designPattern);
    }

    private Map<String, MemberRole> getMembers(Collection<TypeRole> types) {
        Map<String,MemberRole> members = new HashMap<String, MemberRole>();
        for (TypeRole type : types) {
            members.putAll(type.getMembers());
        }
        return members;
    }
}
